home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / prog / pr2mm_send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  13.6 KB  |  579 lines

  1. /*
  2.  *    MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
  3.  *
  4.  *    Department of Electrical Engineering
  5.  *    University of Delaware
  6.  *    Newark, Delaware  19711
  7.  *
  8.  *
  9.  *    Program Channel (inbound): Pass message into MMDF
  10.  *
  11.  *
  12.  *    P R 2 M M _ S E N D . C
  13.  *    =======================
  14.  *
  15.  *    pr2mm_send [-M?] [-D] [-c <channel>] [-h|-v <host>]
  16.  *                        [-s <sender>] [address...]
  17.  *
  18.  *    specify -h if host in US order, -v (for Via:) if in UK order!
  19.  *    specify -Mj if input is JNT mail file.
  20.  *    -Ms is reserved for Batch-SMTP input format (implementation coming)
  21.  *    (default mode: give recipients on command line)
  22.  *
  23.  *    J.B.D.Pardoe
  24.  *    University of Cambridge Computer Laboratory
  25.  *    October 1985
  26.  *    
  27.  *    July 86 - Added #ifdef V4_2BSD around return(status.w_status);    
  28.  *        Added #ifdef NODUP2 - ECB
  29.  */
  30.  
  31. #include <stdio.h>
  32. #ifdef V4_2BSD
  33. #include <sys/wait.h>
  34. #include <sys/file.h>
  35. #endif /* V4_2BSD */
  36. #include <signal.h>
  37. #include "util.h"
  38. #include "mmdf.h"
  39. #include "ch.h"
  40. #include "ap.h"
  41.  
  42.  
  43. #define EX_OK    0 /* everything successful */
  44. #define EX_ADDR    1 /* bad addresses */
  45. #define EX_MECH    2 /* more than just bad addresses */
  46. #define EX_FAIL    3 /* the program failed to behave */
  47.  
  48. #define PR_COMM '#'
  49. #define PR_ERR  '*'
  50.  
  51. /* 
  52.  * Define  SAFEFORK  if  you  want  to  be ultra careful that no mail is
  53.  * lost;  we try and notify the  sender  or  support  that  we  couldn't
  54.  * deliver  some  mail,  but  if  we  can't then the mail will disappear
  55.  * without trace.  Other problems such as  invalid  arguments  may  also
  56.  * cause  this.  If  you  define  SAFEFORK the process doing the work is
  57.  * monitored by another so  that  (as  long  as  mail  can  be  sent  to
  58.  * support) some notification of the error is made.
  59.  */
  60. #define SAFEFORK 
  61.  
  62.  
  63. #define TRY(OPERATION, WHAT) { \
  64.     int rp  = OPERATION; \
  65.     if (rp_isbad (rp)) terminate (WHAT, rp); \
  66. }
  67.  
  68. #define invalid_address(ADR, RPLY) { \
  69.     reportf ("address: %s\nproblem: %s\n", ADR, (RPLY)->rp_line); \
  70. }
  71.  
  72. extern FILE *errmsg_file;
  73. extern long msg_start;
  74. extern char *mmdflogin, *supportaddr;
  75. extern int errno;
  76. extern char *ap_dmflip ();
  77. extern int ap_outtype;
  78.  
  79. static char 
  80.     *basic[]  = {"success", "partial", "temporary", "error"},
  81.     *domain[] = {"syntax", "general", "transfer", "authentication", 
  82.                  "mail", "file system", "<illegal>", "<illegal>"};
  83.  
  84. int prog_debug;
  85. char *sender;
  86. char *newsubargs;
  87.  
  88. char prog_mode;
  89.  
  90. terminate (s, rp)
  91.    char *s; int rp;
  92. {
  93.     printf ("%cfailed to %s\n%c  %s [%03o = %s: %s %o]\n", 
  94.     PR_ERR, s, PR_ERR, rp_valstr (rp), rp & 0377,
  95.     basic[rp_gbbit (rp)], domain[rp_gcbit (rp)], rp_gsbit (rp));
  96.     mm_end (rp);
  97.     exit (EX_MECH);
  98. }    
  99.  
  100. /*  *
  101.  * monitoring of process which does the work
  102.  */
  103.  
  104.  
  105. #ifdef SAFEFORK
  106.  
  107. /*
  108.  * monitor a forked process which does the work
  109.  */
  110.  
  111. char *signame (sig)
  112.     int sig;
  113. {
  114.     static char buff[24];
  115. #ifdef V4_2BSD
  116.     /* I know that the following code does not work on SysVr3 since
  117.      * libc.a doesn't have a "sys_siglist".  Possibly this only works
  118.      * on 4.[23]BSD? -- David Herron <david@ms.uky.edu>
  119.      */
  120.     extern char *sys_siglist[];
  121.  
  122.     if (sig >= 0 && sig < NSIG) {
  123.     return (sys_siglist [sig]);
  124.     } else {
  125.     sprintf (buff, "unknown signal %d", sig);
  126.     return (buff);
  127.     }
  128. #else
  129.     sprintf(buff, "Signal %d", sig);
  130.     return(buff);
  131. #endif
  132. }
  133.  
  134.  
  135. main (argc, argv) 
  136.     int argc; char **argv;
  137. {
  138.     char *divider = "-------------------------------------------------------";
  139.     int child_pid, pp[2];
  140.     char **argv_old = argv;
  141.  
  142.     mmdf_init (*argv);
  143.     
  144.     if (pipe (pp) != 0 || (child_pid = fork ()) == -1) {
  145.     mopen (supportaddr, "Problems with `recvprog' program");
  146.     mprintf ("Failed to start up mail reception program.\n");
  147.     mprintf ("The arguments were:\n");
  148.     while (argc-- != 0) mprintf ("  %s", *argv++);
  149.     mprintf ("\n\nThe message follows\n\%s\n", divider);
  150.     minclude (stdin);
  151.     exit (mclose () == 0 ? EX_MECH : EX_FAIL);
  152.     }
  153.     
  154.     if (child_pid == 0) {
  155. #ifndef NODUP2
  156.     dup2 (pp[1], 1);
  157.     dup2 (pp[1], 2);
  158. #else
  159.     close(1);
  160.     dup (pp[1]);
  161.     close(2);
  162.     dup (pp[1]);
  163. #endif NODUP2
  164.     close (pp[0]);
  165.     child (argc, argv);
  166.     } else {
  167.     int rc, stopped;
  168.     int do_msg = 0;
  169. #ifdef V4_2BSD    /* WIFSTOPPED instead? -- DSH */
  170.     union wait status;
  171. #else
  172.         int status;
  173. #endif /* V4_2BSD */
  174.  
  175.     close (pp[1]);
  176.  
  177.     do {
  178.         rc = wait (&status);
  179.     } while (rc != child_pid && (rc != -1 || errno == EINTR));
  180.  
  181.     if (rc != child_pid) {
  182.         int err = errno;    /* save errno in case open changes... */
  183.         mopen (supportaddr, "Problems with `recvprog' program");
  184.         mprintf ("Failed to collect child's status (pid %d, rc %d, \
  185. error %d).\n\n", child_pid, rc, err);
  186.         do_msg = 1;
  187. #ifdef WIFSTOPPED
  188.     } else if ((stopped = WIFSTOPPED (status)) || WIFSIGNALED (status)) {
  189.         mopen (supportaddr, "Problem with `recvprog' program");
  190.         mprintf ("recvprog was %sed by a signal: %s\n\n",
  191.             (stopped? "stopp":"kill"), signame (status.w_termsig));
  192.         do_msg = 1;
  193.     } else if (status.w_retcode != EX_OK && status.w_retcode != EX_ADDR) {
  194.         int mech = (status.w_retcode == EX_MECH);
  195. #else
  196.         } else if ((stopped = status & 0x80) || status & 0x7F) {
  197.             mopen (supportaddr, "Problem with `recvprog' program");
  198.             mprintf ("recvprog was %sed by a signal: %s\n",
  199.                     (stopped? "stopp":"kill"), signame (status & 0x7F));
  200.             do_msg = 1;        
  201.     } else if ((status>>8)&0xff != EX_OK && (status>>8)&0xff != EX_ADDR) {
  202.         int mech = ((status>>8)&0xff == EX_MECH);
  203. #endif /* WIFSTOPPED */
  204.         mopen (supportaddr, (mech? 
  205.         "recvprog exited with EX_MECH":
  206.         "recvprog exited with unexpected status"));
  207.         if (!mech) 
  208.         mprintf ("recvprog exited with return/status 0x%x.\n\n", 
  209.                             status);
  210.         do_msg = 1;
  211.     }
  212.  
  213.     if (do_msg) {
  214.         FILE *f;
  215.         mprintf ("The arguments were:\n");
  216.         while (argc-- != 0) mprintf ("  %s", *argv++);
  217.  
  218.         mprintf ("\n\nThe program said the following:\n%s\n", divider);
  219.         f = fdopen (pp[0], "r");
  220.         if (f == NULL) 
  221.         mprintf ("[FAILED TO OPEN PIPE]\n"); 
  222.         else 
  223.         minclude (f);
  224.  
  225.         mprintf ("\n%s\n\nThe message follows%s:",
  226.         divider, (fseek (stdin, 0L, 0) < 0) ? 
  227.                 " (couldn't rewind the file)":"");
  228.         mprintf ("\n%s\n", divider);
  229.         minclude (stdin);
  230.         exit (mclose () == 0 ? EX_MECH : EX_FAIL);
  231.     }
  232.  
  233.     if (strcmp (*(argv_old+1), "-D") == 0) {
  234.         char buff [512]; int n;
  235.         while ((n = read (pp[0], buff, 512)) > 0) write (1, buff, n);
  236.     }
  237. #ifdef WIFSTOPPED
  238.     exit (status.w_retcode);
  239. #else
  240.     exit(status);
  241. #endif /* WIFSTOPPED */
  242.     }
  243. }
  244. #endif /* SAFEFORK */
  245.  
  246.  
  247. /*  *
  248.  * pass a message into MMDF
  249.  */
  250.  
  251.  
  252. #ifdef SAFEFORK
  253. #define MAIN child
  254. #else
  255. #define MAIN main
  256. #endif /* SAFEFORK */
  257.  
  258.  
  259. #define HT_NONE 0 /* no host specified */
  260. #define HT_HOST 1 /* host specified by -h */
  261. #define HT_VIA  2 /* host specified by -v */
  262.  
  263.  
  264. MAIN (argc, argv)
  265.     int argc; char **argv;
  266. {
  267.     char *channel, *host, *arg;
  268.     struct rp_bufstruct rply; int rply_len;
  269.     int rp, ex = EX_OK, n, hosttype = HT_NONE;
  270.     char buf[BUFSIZ], subargs[32]; 
  271.  
  272.     errmsg_file = NULL;
  273.     sender = 0;
  274.     prog_mode = '\0';
  275.  
  276. #ifndef SAFEFORK
  277.     mmdf_init (*argv);
  278. #endif /* SAFEFORK */
  279.  
  280.     TRY (mm_init (), "initialize MMDF");
  281.     TRY (mm_sbinit (), "initialize submission");
  282.  
  283.     while (--argc > 0 && *(arg = *++argv) == '-') {
  284.     char opt = *++arg;
  285.     char **where = 0;
  286.     switch (opt) {
  287.         case 'D': prog_debug = 1;   break;
  288.         case 'c': where = &channel; break;
  289.         case 's': where = &sender;  break;
  290.         case 'S': where = &newsubargs; break;
  291.  
  292.         case 'h': 
  293.         case 'v': 
  294.         if (hosttype != HT_NONE) {
  295.             printf ("%chost specified twice\n", PR_ERR);
  296.             exit (EX_MECH);
  297.         }
  298.         hosttype = (opt == 'h' ? HT_HOST : HT_VIA);
  299.         where = &host; break;
  300.  
  301.         case 'M':
  302.         prog_mode = *arg; break;
  303.  
  304.         default:
  305.         printf ("%cunknown argument -%c\n", PR_ERR, *arg);
  306.         exit (EX_MECH);
  307.     }
  308.     if (where != 0) {
  309.         if (--argc <= 0) {
  310.         printf ("%cno value for -%c\n", PR_ERR, *arg);
  311.         exit (EX_MECH);
  312.         }
  313.         *where = *++argv;
  314.     }
  315.     }
  316.  
  317.     if (prog_mode == 'j' && argc > 0) {        /* JNT mail mode */
  318.     printf ("%c-Mj and recipients", PR_ERR);
  319.     exit (EX_MECH);
  320.     } else if (prog_mode == 's' && argc > 0) {    /* Batch-SMTP mail mode */
  321.     printf ("%c-Ms and recipients", PR_ERR);
  322.     exit (EX_MECH);
  323.     } else if (argc == 0) {
  324.     printf ("%cno recipients\n", PR_ERR);
  325.     exit (EX_MECH);
  326.     }
  327.         
  328.     /* Set a default timeout of 30 seconds -- the rational is that
  329.      * recvprog will normally be called from some background daemon.
  330.      * We're trying to avoid nameserver timeouts. -- DSH
  331.      */
  332.     strcpy (subargs, "tmlvk30*");
  333.     if (channel) {
  334.         Chan *curchan;
  335.  
  336.     if ((curchan = ch_nm2struct (channel)) == (Chan *) NOTOK)
  337.         err_abrt (RP_PARM, "unknown channel name '%s'", channel);
  338.         ch_llinit(curchan);
  339.     sprintf (buf, "%si%s*", subargs, channel);
  340.     strcpy (subargs, buf);
  341.     }
  342.     if (hosttype != HT_NONE) {
  343.     sprintf (buf, "%sh%s*", subargs, 
  344.                 (hosttype == HT_VIA ? ap_dmflip (host) : host));
  345.     strcpy (subargs, buf);
  346.     }
  347.     if (!sender) {
  348.     strcat (subargs, "s");
  349.     }
  350.  
  351.     if (prog_mode == 'j') {
  352.     ex = JNTextract_recipients (&argc, &argv);
  353.     if (ex != EX_OK) {
  354.         if (errmsg_file != NULL) {
  355.         errmsg_send ();
  356.         }
  357.         exit (ex);
  358.     }
  359.     } else if (prog_mode == 's') {
  360.         /* Batch SMTP - not implemented yet */
  361.         printf ("%cBatch SMTP not supported yet", PR_ERR);
  362.         exit(EX_MECH);
  363.     }
  364.  
  365. #ifdef DEBUG
  366.     if (prog_debug) {
  367.     printf ("%csubargs: %s", PR_COMM, subargs);
  368.     printf ("; sender %s", sender ? sender : "(unspecified)");
  369.     printf ("; %d recipient(s)\n", argc);
  370.     }
  371. #endif
  372.  
  373.     TRY (mm_winit ((char *) 0, subargs, sender), "initialize for message");
  374.     TRY (mm_rrply (&rply, &rply_len), "get result of mm_winit");
  375.  
  376.     switch (rp_gbval (rply.rp_val))
  377.     {              /* was source acceptable?            */
  378.     case RP_BNO:
  379.         case RP_BTNO:
  380.         terminate(rply.rp_line, rply.rp_val);
  381.     }
  382. #ifdef DEBUG
  383.     if (prog_debug) {
  384.     printf ("%csubmitting addresses\n", PR_COMM); fflush (stdout);
  385.     }
  386. #endif
  387.     while (argc--) { 
  388.     char *adr = *argv++;
  389. #ifdef DEBUG
  390.     if (prog_debug) {
  391.         printf ("%c  %s:\t", PR_COMM, adr); fflush (stdout);
  392.     }
  393. #endif /* DEBUG */
  394.     TRY (mm_wadr ((char *) 0, adr), "write address");
  395.     TRY (mm_rrply (&rply, &rply_len), "get result of writing address");
  396. #ifdef DEBUG
  397.     if (prog_debug) {
  398.         printf ("[%o] %s\n", rply.rp_val & 0377, rply.rp_line); 
  399.         fflush (stdout);
  400.     }
  401. #endif /* DEBUG */
  402.     switch (rp = rp_gval (rply.rp_val)) {
  403.         case RP_AOK:
  404.         case RP_DOK:
  405.         break;
  406.         case RP_USER:
  407.         case RP_NS:
  408.         invalid_address (adr, &rply);
  409.         break;
  410.         default:
  411.         {
  412.             char buff [512];
  413.             sprintf (buff, "understand reply to %s:\n%c%s",
  414.                         adr, PR_ERR, rply.rp_line);
  415.             terminate (buff, rp);
  416.         }
  417.     }
  418.     }
  419.  
  420.     TRY (mm_waend (), "finish writing addresses");
  421.  
  422.     while (n = fread (buf, sizeof (char), BUFSIZ, stdin)) {
  423.     TRY (mm_wtxt (buf, n), "write text");
  424.     }
  425.  
  426.     TRY (mm_wtend (), "finish writing text");
  427.     TRY (mm_rrply (&rply, &rply_len), "get result of submission");
  428.  
  429.     switch (rp = rp_gval (rply.rp_val)) {
  430.     case RP_MOK:
  431.         break;
  432.  
  433.     case RP_NDEL:
  434.         if (errmsg_file == NULL) {
  435.         printf ("%csubmit returned NDEL but no error message\n",
  436.             PR_ERR);
  437.         exit (EX_MECH);
  438.         }
  439.         break;
  440.  
  441.     default:
  442.         if (errmsg_file != NULL) {
  443.         printf ("%csending error message\n", PR_COMM);
  444.         errmsg_send ();
  445.         }
  446.         terminate ("understand reply from submit", rp);
  447.         break;
  448.     }
  449.  
  450.     mm_sbend ();
  451.     mm_end (RP_OK);
  452.  
  453.     if (errmsg_file != NULL) {
  454.     errmsg_send ();
  455.     ex = EX_ADDR;
  456.     }
  457.     exit (ex);
  458.     
  459. }
  460.  
  461.  
  462. /*  *
  463.  * reading of addresses from JNT mail file header
  464.  *
  465.  * (Strictly we should be using the MMDF parsing routines in this
  466.  * code, but I'm fed up trying to get the buggers to work!!  This 
  467.  * works more or less...!)
  468.  */
  469.  
  470. JNTextract_recipients (argc, argv)
  471.     int *argc; char ***argv;
  472. {
  473.     struct alist {
  474.     struct alist *ad_next;
  475.     char ad_addr[1]; /* well, as long as we need */
  476.     } *alist = 0;
  477.     int naddrs = 0;
  478.     char **pp;
  479.  
  480.     rewindable_msg ();
  481.  
  482.     for (;;) {
  483.     int ch;
  484.     int lit  = 0; /* in a domain literal */
  485.     int lay  = 0; /* just had layout */
  486.     enum { D_NO, D_ADR, D_END } done = D_NO;
  487.     char buff[ADDRSIZE];
  488.     register char *p;
  489.     struct alist *al;
  490.  
  491.     p = &buff[0];
  492.  
  493.     while (done == D_NO) {
  494.         enum { T_CHAR, T_SEP, T_LAY } type = T_CHAR; /* char type */
  495.         switch (ch = getchar ()) {
  496.         case '\\' :
  497.             *p++ = '\\'; ch = getchar (); break;
  498.         case '[' :
  499.             lit = 1; break;
  500.         case ']' :
  501.             lit = 0; break;
  502.         case ',' :
  503.             if (!lit) type = T_SEP; break;
  504.         case '\r' :
  505.             ch = getchar ();
  506.             if (ch == '\n') {
  507.             type = T_LAY;
  508.             } else {
  509.             ungetc (ch, stdin);
  510.             ch = '\r';
  511.             }
  512.             break;
  513.         case '\n' :
  514.             type =T_LAY; break;
  515.         case EOF :
  516.             reportf ("%cJNT file ended prematurely\n", PR_COMM);
  517.             return (EX_MECH); 
  518.         default :
  519.             break;
  520.         }
  521.         
  522.         switch (type) {
  523.         case T_SEP :
  524.             done = D_ADR; break;
  525.         case T_CHAR :
  526.             *p++ = ch;
  527.             lay = 0; 
  528.             break;
  529.         case T_LAY :
  530.             if (lay) done = D_END; else lay = 1;
  531.             break;
  532.         }
  533.     }
  534.  
  535.     *p = '\0';
  536.     al = (struct alist *) malloc (
  537.         sizeof (*al) - sizeof ((*al).ad_addr) + 
  538.         strlen (buff) + 1);
  539.     al->ad_next = alist; alist = al;
  540.     strcpy (al->ad_addr, buff);
  541.     naddrs++;
  542. #ifdef DEBUG
  543.     if (prog_debug) printf ("%caddress %d: %s%s\n", 
  544.             PR_COMM, naddrs, buff, (done==D_END? " !":""));
  545. #endif
  546.     if (done == D_END) break;
  547.     }
  548.  
  549.     msg_start = ftell (stdin);
  550.     
  551.     *argc = naddrs;
  552.     *argv = pp = (char **) malloc (naddrs * sizeof (char *));
  553.  
  554.     while (naddrs-- > 0) {
  555.     *pp++ = alist->ad_addr; alist = alist->ad_next;
  556.     }
  557.     return (EX_OK);
  558. }
  559.  
  560. /*  *
  561.  * report an invalid address or other problem
  562.  */
  563.  
  564.     
  565. reportf (f, a0, a1, a2, a3, a4, a5, a6, a7)
  566.     char *f;
  567. {
  568. #ifdef DEBUG
  569.     if (prog_debug) {
  570.     printf (f, a0, a1, a2, a3, a4, a5, a6, a7);
  571.     }
  572. #endif
  573.  
  574.     if (errmsg_file == NULL) errmsg_open ();
  575.     fprintf (errmsg_file, f, a0, a1, a2, a3, a4, a5, a6, a7);
  576.     fprintf (errmsg_file, "\n");
  577. }
  578.  
  579.